# coding: utf-8

# -------------------------------------------------------------------------------
# Name:         report_service.py
# Description:
# Author:       XiangjunZhao
# EMAIL:        2419352654@qq.com
# Date:         2022/8/18 08:58
# -------------------------------------------------------------------------------
import re
from datetime import datetime
import logging
from abc import ABCMeta, abstractmethod

from apps.CeleryScheduledTaskService.SystemService.send_mail_task import send_mail
from apps.HttpAutoTestService.core.builtin.functions import ms_fmt_hms
from apps.HttpAutoTestService.services.result_info_service import TestcaseResultInfoServiceImpl, \
    ExtMethodResultInfoServiceImpl, SQLResultInfoServiceImpl
from apps.SystemService.models import Parameter
from utils.dingtalk_client import DingTalkClient
from utils.feishu_client import FeiShuClient
from utils.qiwei_client import QiWeiClient

logger = logging.getLogger(__name__)

# 绝对http url正则表达式
absolute_http_url_regexp = re.compile(r"^https?://", re.I)


class ClientFactory(metaclass=ABCMeta):
    @abstractmethod
    def create_client(self):
        pass


class DingTalkClientFactory(ClientFactory):
    def create_client(self):
        dingtalk_parameter = Parameter.objects.filter(key='DINGTALK', is_deleted=False).first()
        if dingtalk_parameter:
            dingtalk_parameter_value = dingtalk_parameter.value
            webhook = dingtalk_parameter_value.get('WEBHOOK')
            secret = dingtalk_parameter_value.get('SECRET') or None
            if webhook:
                try:
                    return DingTalkClient(webhook=webhook, secret=secret)
                except Exception as e:
                    logger.error(f'创建钉钉客户端失败，原因：{e}')
                    raise e
            else:
                logger.info('webhook为空，创建钉钉客户端失败')
        else:
            logger.warning('获取钉钉配置参数失败')


class QiWeiClientFactory(ClientFactory):
    def create_client(self):
        qiwei_parameter = Parameter.objects.filter(key='QIWEI', is_deleted=False).first()
        if qiwei_parameter:
            qiwei_parameter_value = qiwei_parameter.value
            webhook = qiwei_parameter_value.get('WEBHOOK')
            if webhook:
                try:
                    return QiWeiClient(webhook=webhook)
                except Exception as e:
                    logger.error(f'创建企微客户端失败，原因：{e}')
                    raise e
            else:
                logger.info('webhook为空，创建企微客户端失败')
        else:
            logger.warning('获取企微配置参数失败')


class FeiShuClientFactory(ClientFactory):
    def create_client(self):
        feishu_parameter = Parameter.objects.filter(key='FEISHU', is_deleted=False).first()
        if feishu_parameter:
            feishu_parameter_value = feishu_parameter.value
            webhook = feishu_parameter_value.get('WEBHOOK')
            secret = feishu_parameter_value.get('SECRET') or None
            if webhook:
                try:
                    return FeiShuClient(webhook=webhook, secret=secret)
                except Exception as e:
                    logger.error(f'创建飞书客户端失败，原因：{e}')
                    raise e
            else:
                logger.info('webhook为空，创建飞书客户端失败')
        else:
            logger.warning('获取飞书配置参数失败')


class ReportService(object):
    def __init__(self, report_type, version, executor, is_periodictask):
        """
        测试报告
        Args:
            report_type: 报告类型（testcase、testsuite）
            version: 版本号
            executor: 当前执行(登录)用户
            is_periodictask: 标记是否是定时任务

        Returns:

        """
        self.report_type = report_type
        self.version = version
        self.subject = '用例测试报告' if report_type == 'testcase' else '场景测试报告'
        self.executor_real_name = '定时任务' if is_periodictask else executor.real_name
        self.execute_time = datetime.fromtimestamp(int(version) / 1000).strftime("%Y-%m-%d %H:%M:%S")
        self.total_count = 0
        self.total_success = 0
        self.total_fail = 0
        self.total_elapsed_ms = '00:00:00.000'
        self.success_pct = 0.00
        self.report_url = ""
        # 是否发送报告(钉钉)
        self.send_dingtalk_report = False
        # 是否发送报告(飞书)
        self.send_feishu_report = False
        # 是否发送报告(企微)
        self.send_qiwei_report = False
        # 是否发送报告(邮件)
        self.send_email_report = False
        # 收件人
        self.to = ""
        # 抄送人
        self.cc = ""

        report_parameter = Parameter.objects.filter(key='REPORT', is_deleted=False).first()
        if report_parameter:
            report_parameter_value = report_parameter.value
            self.send_dingtalk_report = report_parameter_value.get('SEND_DINGTALK_REPORT')
            self.send_feishu_report = report_parameter_value.get('SEND_FEISHU_REPORT')
            self.send_qiwei_report = report_parameter_value.get('SEND_QIWEI_REPORT')
            self.send_email_report = report_parameter_value.get('SEND_EMAIL_REPORT')
            self.to = report_parameter_value.get('TO')
            self.cc = report_parameter_value.get('CC')
            url = report_parameter_value.get('URL', '').strip('/')
            if not absolute_http_url_regexp.match(url.lower()):
                url = f'https://{url}'
            self.report_url = f'{url}/#/QAPlatform/HttpAutoTestService/report/{report_type}/{version}'
            if any([self.send_dingtalk_report, self.send_feishu_report, self.send_qiwei_report,
                    self.send_email_report]):
                self.__build_report()

    def __build_report(self):
        if self.report_type == 'testcase':
            testcase_results, total_count, total_success, total_fail, total_elapsed_ms = \
                TestcaseResultInfoServiceImpl().result_info(self.version)
        else:
            # 统计测试用例结果
            testcase_results, testcase_result_total, testcase_result_success, testcase_result_fail, total_elapsed_ms1 = \
                TestcaseResultInfoServiceImpl().result_info(self.version)
            # 统计扩展方法结果
            ext_method_results, ext_method_result_total, ext_method_result_success, ext_method_result_fail, total_elapsed_ms2 = \
                ExtMethodResultInfoServiceImpl().result_info(self.version)
            # 统计sql执行结果
            sql_results, sql_result_total, sql_result_success, sql_result_fail, total_elapsed_ms3 = \
                SQLResultInfoServiceImpl().result_info(self.version)

            # 测试用例、扩展方法、sql执行总耗时
            total_elapsed_ms = total_elapsed_ms1 + total_elapsed_ms2 + total_elapsed_ms3
            # 测试用例结果、扩展方法结果、sql执行结果总数
            total_count = testcase_result_total + ext_method_result_total + sql_result_total
            # 测试用例结果、扩展方法结果、sql执行结果成功总数
            total_success = testcase_result_success + ext_method_result_success + sql_result_success
            # 测试用例结果、扩展方法结果、sql执行结果失败总数
            total_fail = testcase_result_fail + ext_method_result_fail + sql_result_fail
        # 执行总耗时
        total_elapsed_ms = ms_fmt_hms(total_elapsed_ms)
        # 结果成功数百分比
        try:
            success_pct = round((total_success / total_count) * 100, 2)
        except ZeroDivisionError:
            success_pct = 0
        self.total_count = total_count
        self.total_success = total_success
        self.total_fail = total_fail
        self.total_elapsed_ms = total_elapsed_ms
        self.success_pct = success_pct

    def send_report(self):
        # 是否发送报告(钉钉)
        if self.send_dingtalk_report:
            dingtalk_client = DingTalkClientFactory().create_client()
            if dingtalk_client:
                content = f"""
**<font color=#2d8cf0>{self.subject}</font>**\n
成功率：**<font color=#19be6b>{self.success_pct} %</font>**\n
执行用例总数：**{self.total_count}**\n
成功用例数：**<font color=#19be6b>{self.total_success}</font>**\n
失败用例数：**<font color=#ed4014>{self.total_fail}</font>**\n
测试执行人：{self.executor_real_name}\n
执行总时长：{self.total_elapsed_ms}\n
执行时间：{self.execute_time}\n
[<font color=#2db7f5>点击查看测试报告<font/>]({self.report_url})
                """
                dingtalk_client.send_markdown(title=self.subject, text=content)
        # 是否发送报告(飞书)
        if self.send_feishu_report:
            feishu_client = FeiShuClientFactory().create_client()
            if feishu_client:
                content = {
                    "config": {
                    },
                    "header": {
                        "title": {
                            "content": self.subject,
                            "tag": "plain_text"
                        },
                        "template": "blue"
                    },
                    "elements": [
                        {
                            "tag": "div",
                            "text": {
                                "tag": "lark_md",
                                "content": f"成功率：**{self.success_pct} %**\n执行用例总数：**{self.total_count}**\n成功用例数：**{self.total_success}**\n失败用例数：**{self.total_fail}**\n测试执行人：{self.executor_real_name}\n执行总时长：{self.total_elapsed_ms}\n执行时间：{self.execute_time}"
                            },
                        },
                        {
                            "tag": "div",
                            "text": {
                                "tag": "lark_md",
                                "content": f"[点击查看测试报告]({self.report_url})"
                            }
                        }
                    ],
                }
                feishu_client.send_card(content)
        # 是否发送报告(企微)
        if self.send_qiwei_report:
            qiwei_client = QiWeiClientFactory().create_client()
            if qiwei_client:
                content = f"""
## <font color=#2d8cf0>{self.subject}</font>\n
> 成功率：**<font color=#19be6b>{self.success_pct} %</font>**
> 执行用例总数：**{self.total_count}**
> 成功用例数：**<font color=#19be6b>{self.total_success}</font>**
> 失败用例数：**<font color=#ed4014>{self.total_fail}</font>**
> 测试执行人：{self.executor_real_name}
> 执行总时长：{self.total_elapsed_ms}
> 执行时间：{self.execute_time}\n
[点击查看测试报告]({self.report_url})
                """
                qiwei_client.send_markdown(content=content)
        # 是否发送报告(邮件)
        if self.send_email_report:
            if not self.to:
                logger.warning('收件人为空，邮件发送测试报告失败')
            to = self.to.split(',')
            cc = self.cc.split(',') if self.cc else None
            try:
                mail_body = f"""
{self.subject}
成功率：{self.success_pct} %
执行用例总数：{self.total_count}
成功用例数：{self.total_success}
失败用例数：{self.total_fail}
测试执行人：{self.executor_real_name}
执行总时长：{self.total_elapsed_ms}
执行时间：{self.execute_time}
测试报告访问链接：{self.report_url}
                """
                send_mail(subject=self.subject, body=mail_body, to=to, cc=cc)
            except Exception as e:
                logger.error(f'邮件发送测试报告失败，原因：{e}')
                raise e
            else:
                logger.info('邮件发送测试报告成功')


if __name__ == '__main__':
    res = DingTalkClientFactory().create_client()
    print(res)
